﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using SpiritEngine;
using SpiritEngine.Components2D;

using SimNations.Pathfinding;


namespace SimNations.City
{
    public abstract class ACity : AComponent
    {
        // MEMBER VARIABLES
        // ------------------------------------------------------------------------------------------------------------------------

        protected int m_CityHeight;
        protected int m_CityWidth;

        protected CityTile[,] m_CityGrid = null;

        protected PathFinder m_PathFinder;

        protected Vector2 m_Position = Vector2.Zero;

        protected Random m_Random;


        // CONSTRUCTORS
        // ------------------------------------------------------------------------------------------------------------------------

        public ACity()
        {
            m_CityHeight = 64;
            m_CityWidth = 64;

            m_Random = new Random();

        } // end ACity::ACity()

        public ACity(int Height, int Width)
        {
            m_CityHeight = Height;
            m_CityWidth = Width;

            m_Random = new Random();

        } // end ACity::ACity(int, int)



        // PRIVATE/PROTECTED METHODS
        // ------------------------------------------------------------------------------------------------------------------------

        protected Vector2 GetNearestTransitTile(Vector2 vPos, TransitTypes transitType)
        {
            Vector2 checkPos;
            CityTile transitTile = null;
            
            List<CityTile> list = new List<CityTile>();

            int distance = 0;   // Keeps track of the distance we are checking at.

            while (transitTile == null)
            {
                list.Clear();
                distance++;

                // Check tiles that are distance squares away from vPos, and add them to the
                // list if they are road tiles.
                for (int y = -distance; y <= distance; y += distance)
                {
                    for (int x = -1; x <= 1; x++)
                    {
                        checkPos.X = vPos.X + x;
                        checkPos.Y = vPos.Y + y;

                        if ((checkPos.X >= 0 && checkPos.X < m_CityWidth) &&
                             (checkPos.Y >= 0 && checkPos.Y < m_CityHeight))
                        {
                            if (m_CityGrid[(int)checkPos.X, (int)checkPos.Y].TransitType == transitType)
                                list.Add(m_CityGrid[(int)checkPos.X, (int)checkPos.Y]);
                        }

                    }
                }


                // Check if we found any road tiles at the current distance from vPos.
                if (list.Count > 1)
                {
                    // We have a tie for closest transit tile so choose one at random.                   
                    transitTile = list[m_Random.Next(0, list.Count)];
                }
                else if (list.Count == 1)
                {
                    transitTile = list[0];
                }

            } // end while


            return transitTile.Position;

        } // end ACity::GetNearestRoadTile(Vector2)
        

        protected virtual void InitCityGrid()
        {

        } // end ACity::InitCityGrid()

        protected virtual void InitPathFinder()
        {
            m_PathFinder = new PathFinder();


            m_PathFinder.TransitType = TransitTypes.Road;
            
            m_PathFinder.World = this.m_CityGrid;
            m_PathFinder.WorldWidth = this.m_CityWidth;
            m_PathFinder.WorldHeight = this.m_CityHeight;

        } // end ACity::InitPathFinder();

        protected override void Load()
        {
            InitCityGrid();
            InitPathFinder();

        } // end ACity::Load()


        // METHODS
        // ------------------------------------------------------------------------------------------------------------------------

        public override void Update()
        {
            CID_Keyboard keyboard = (CID_Keyboard) this.ParentGameScreen.Engine.Services.GetService(typeof(CID_Keyboard));


            int inc = 1; // how much (in pixels) to move the screen each time an arrow key is pressed



            if (keyboard.WasKeyPressed(Keys.Right) || keyboard.WasKeyHeld(Keys.Right))
            {
                m_Position.X -= inc;
            }
            else if (keyboard.WasKeyPressed(Keys.Left) || keyboard.WasKeyHeld(Keys.Left))
            {
                m_Position.X += inc;
            }

            if (keyboard.WasKeyPressed(Keys.Down) || keyboard.WasKeyHeld(Keys.Down))
            {
                m_Position.Y -= inc;
            }
            else if (keyboard.WasKeyPressed(Keys.Up) || keyboard.WasKeyHeld(Keys.Up))
            {
                m_Position.Y += inc;
            }


            // System.Diagnostics.Debug.WriteLine("Updating city...");
            // System.Diagnostics.Debug.WriteLine("X: " + m_Position.X);
            // System.Diagnostics.Debug.WriteLine("Y: " + m_Position.Y);


            // Limit how far the screen can scroll.
            // What we are doing here is making it so the screen is not allowed to scroll more than 100 pixels
            // beyond any edge of the city.
            if (m_Position.X < -100)
                m_Position.X = -100;
            else if (m_Position.X > (m_CityWidth * 32) )
                m_Position.X = (m_CityWidth * 32);

            if (m_Position.Y < -100)
                m_Position.Y = -100;
            else if (m_Position.Y > (m_CityHeight * 32) )
                m_Position.Y = (m_CityHeight * 32);

        } // end ACity::Update()

        public override void Draw()
        {

        } // end ACity::Draw()


        // DEBUG METHODS
        // ------------------------------------------------------------------------------------------------------------------------

#if (DEBUG)
        // put all debug methods in here...
#endif


        // PROPERTIES
        // ------------------------------------------------------------------------------------------------------------------------

        public int CityHeight
        {
            get
            {
                return m_CityHeight;
            }
        } // end property CityHeight

        public int CityWidth
        {
            get
            {
                return m_CityWidth;
            }
        } // end property CityWidth

        public Engine Engine
        {
            get
            {
                return ParentGameScreen.Engine;
            }
        } // end property Engine

        // This is used for moving the city around when the user scrolls the screen.
        public Vector2 Position
        {
            get
            {
                return m_Position;
            }
            set
            {
                m_Position = value;
            }
        } // end property Position



        // EVENTS
        // ------------------------------------------------------------------------------------------------------------------------



    } // end class City
}
